home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
irsim-ca.2
/
irsim-ca
/
irsim-cap-9.2
/
src
/
ana11
/
window.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-15
|
27KB
|
1,193 lines
/*
* *********************************************************************
* * Copyright (C) 1988, 1990 Stanford University. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. Stanford University *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
/*
* Window Manager for logic analyzer
*
*/
#include <stdio.h>
#include "ana.h"
#include <X11/Xutil.h>
#include "graphics.h"
#include "ana_glob.h"
public Display *display = NULL;
public Screen *screen;
public Window window = 0;
public Window iconW = 0;
public int CHARHEIGHT = 0;
public int CHARWIDTH = 0;
public int descent;
public Times tims;
public Traces traces;
public Wstate windowState = { FALSE, FALSE, FALSE };
private char *wname = "analyzer";
public char *banner;
public int bannerLen;
private void DrawSignal(), DrawVector(), EraseCursor(), DrawCursor();
private void MoveCursorToPos();
/*
* Convert a time to its corresponding x position.
*/
public
#define TimeToX( tm ) \
(((tm) - tims.start) * (traceBox.right - traceBox.left - 2) / \
tims.steps + traceBox.left + 1 )
/*
* Convert an x position to the closest time-step.
* Return -1 if the point lies outside the traces window.
*/
public TimeType XToTime( x )
Coord x;
{
float tmp;
if( (x <= traceBox.left) or (x >= traceBox.right) )
return( -1 );
tmp = (float) tims.steps / (traceBox.right - traceBox.left - 2);
return( tims.start + round( (x - traceBox.left - 1) * tmp ) );
}
/*
* return TRUE if the 2 bounding boxes intersect, otherwise FALSE
*/
#define Intersect( b1, b2 ) \
( ( (b1.top > b2.bot) or (b2.top > b1.bot) or \
(b1.left > b2.right) or (b2.left > b1.right ) ) ? FALSE : TRUE )
/*
* Initialize the windows and various other metrics.
*/
public int InitDisplay( fname, display_unit )
char *fname;
char *display_unit;
{
XFontStruct *font;
if( display == NULL )
{
if( (display = XOpenDisplay( display_unit )) == NULL )
{
fprintf( stderr, "could not open display\n" );
return( FALSE );
}
screen = ScreenOfDisplay( display, DefaultScreen( display ) );
}
if( CHARHEIGHT == 0 )
{
char *fontname;
fontname = GetXDefault( DEFL_FONT );
if( (font = XLoadQueryFont( display, fontname )) == NULL )
{
fprintf( stderr, "Could not load font `%s'", fontname );
if( not IsDefault( DEFL_FONT, fontname ) )
{
fontname = ProgDefault( DEFL_FONT );
if( (font = XLoadQueryFont( display, fontname )) == NULL )
{
fprintf( stderr, " or `%s'\n", fontname );
return( FALSE );
}
else
fprintf( stderr, " using `%s' instead\n", fontname );
}
else
{
fprintf( stderr, "\n" );
return( FALSE );
}
}
CHARHEIGHT = font->max_bounds.ascent + font->max_bounds.descent;
CHARWIDTH = font->max_bounds.width;
descent = font->max_bounds.descent;
InitGraphics( font->fid );
}
banner = (fname != NULL and *fname != '\0') ? fname : wname;
bannerLen = strlen( banner );
if( iconW == 0 )
iconW = CreateIconWindow( 10, 10 );
if( window == 0 )
{
InitWindow( TRUE, NormalState, 0, 0, 0, 0, 10, 10 );
InitMenus();
}
if( not InitHandler( ConnectionNumber( display ) ) )
return( FALSE );
return( TRUE );
}
public int InitWindow( firstTime, state, x, y, w, h, ix, iy )
int firstTime;
int state;
Coord x, y, w, h;
Coord ix, iy;
{
int spec, u_spec;
static int b;
char *geo;
XSizeHints shint;
XWMHints wmh;
XSetWindowAttributes att;
XClassHint class;
if( firstTime )
{
b = atoi( GetXDefault( DEFL_BDRWIDTH ) );
if( b <= 0 )
b = atoi( ProgDefault( DEFL_BDRWIDTH ) );
geo = ProgDefault( DEFL_GEOM );
spec = XParseGeometry( geo, &x, &y, &w, &h );
geo = GetXDefault( DEFL_GEOM );
u_spec = IsDefault( DEFL_GEOM, geo ) ? FALSE : TRUE;
if( u_spec )
spec = XParseGeometry( geo, &x, &y, &w, &h );
if( (spec & (XValue | XNegative)) == (XValue | XNegative) )
x += WidthOfScreen( screen ) - w - 2 * b;
if( (spec & (YValue | YNegative)) == (YValue | YNegative) )
y += HeightOfScreen( screen ) - h - 2 * b;
XWINDOWSIZE = w;
YWINDOWSIZE = h;
}
else
u_spec = TRUE;
att.background_pixel = colors.white;
att.border_pixmap = pix.gray;
att.backing_planes = colors.black | colors.white | colors.hilite |
colors.traces | colors.banner_bg | colors.banner_fg;
att.cursor = cursors.deflt;
window = XCreateWindow( display, RootWindowOfScreen( screen ),
x, y, w, h, b, DefaultDepthOfScreen( screen ), InputOutput,
(Visual *) CopyFromParent,
(CWBackPixel | CWBorderPixmap | CWBackingPlanes | CWCursor), &att );
XStoreName( display, window, wname );
XSetIconName( display, window, wname );
class.res_name = "irsim";
class.res_class = wname;
XSetClassHint( display, window, &class );
wmh.input = True;
wmh.initial_state = state;
wmh.icon_pixmap = pix.icon;
wmh.icon_window = iconW;
wmh.icon_x = ix;
wmh.icon_y = iy;
wmh.flags = InputHint | StateHint | IconPixmapHint | IconWindowHint |
IconPositionHint;
XSetWMHints( display, window, &wmh );
shint.x = x;
shint.y = y;
shint.width = w;
shint.height = h;
shint.max_width = shint.max_height = 16000; /* any big number */
shint.width_inc = shint.height_inc = 1;
GetMinWsize( &shint.min_width, &shint.min_height );
shint.flags = ( u_spec ) ?
( PMinSize | PMaxSize | PResizeInc | USPosition | USSize ) :
( PMinSize | PMaxSize | PResizeInc | PPosition | PSize );
XSetNormalHints( display, window, &shint );
XSelectInput( display, window, ExposureMask | StructureNotifyMask |
KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask );
XFlush( display );
}
public
#define DEF_STEPS 4 /* default simulation steps per screen */
/*
* Initialize the display times so that when first called the last time is
* shown on the screen. Default width is DEF_STEPS (simulation) steps.
*/
public void InitTimes( firstT, stepsize, lastT )
TimeType firstT, stepsize, lastT;
{
tims.first = firstT;
tims.last = lastT;
tims.steps = 4 * stepsize;
if( autoScroll or tims.start <= tims.first )
{
if( lastT < tims.steps )
{
tims.start = tims.first;
tims.end = tims.start + tims.steps;
}
else
{
tims.end = lastT + 2 * stepsize;
tims.start = tims.end - tims.steps;
if( tims.start < tims.first )
{
stepsize = tims.first - tims.start;
tims.start += stepsize;
tims.end += stepsize;
}
}
}
tims.cursor = -1;
}
/*
* Redraw any region that overlaps the redraw-box.
*/
public void RedrawWindow( box )
BBox box;
{
if( Intersect( bannerBox, box ) )
RedrawBanner();
if( Intersect( timesBox, box ) )
RedrawTimes();
if( Intersect( namesBox, box ) )
RedrawNames( box );
if( Intersect( scrollBox, box ) )
DrawScrollBar( TRUE );
if( Intersect( cursorBox, box ) )
DrawCursVal( box );
if( Intersect( textBox, box ) )
RedrawText();
if( Intersect( traceBox, box ) )
RedrawTraces( &box );
}
/*
* Displays the window banner.
*/
public void RedrawBanner()
{
Menu *mp;
FillBox( window, bannerBox, gcs.bannerBg );
XCopyArea( display, pix.iconbox, window, gcs.bannerFg, 0, 0, 13, 13,
iconBox.left, iconBox.top );
StrLeft( window, banner, bannerLen, iconBox.right + 4,
(bannerBox.bot - 2 + CHARHEIGHT) / 2, gcs.bannerFg );
if( windowState.selected )
{
if( selectBox.right > selectBox.left )
FillBox( window, selectBox, gcs.select );
FillAREA( window, bannerBox.left, bannerBox.bot - 1, bannerBox.right -
bannerBox.left + 1, 2, gcs.border );
XSetWindowBorder( display, window, colors.border );
}
else
{
FillAREA( window, bannerBox.left, bannerBox.bot - 1, bannerBox.right -
bannerBox.left + 1, 2, gcs.gray );
XSetWindowBorderPixmap( display, window, pix.gray );
}
for( mp = menu; mp->str != NULL; mp++ )
{
StrCenter( window, mp->str, mp->len, mp->box.left, mp->box.right,
mp->box.bot, gcs.bannerFg );
}
XCopyArea( display, pix.sizebox, window, gcs.bannerFg, 0, 0, 13, 13,
sizeBox.left, sizeBox.top );
}
public void WindowCrossed( selected )
int selected;
{
GC color;
if( selected == windowState.selected )
return;
windowState.selected = selected;
if( selected )
XSetWindowBorder( display, window, colors.border );
else
XSetWindowBorderPixmap( display, window, pix.gray );
if( windowState.tooSmall )
return;
if( selectBox.right > selectBox.left )
{
if( selected )
FillBox( window, selectBox, gcs.select );
else
FillBox( window, selectBox, gcs.bannerBg );
}
FillAREA( window, bannerBox.left, bannerBox.bot - 1, XWINDOWSIZE - 1, 2,
selected ? gcs.border : gcs.gray );
}
public void RedrawSmallW()
{
static char *msg = "I'm too small";
Coord y;
int len;
XClearWindow( display, window );
len = strlen( msg );
y = (YWINDOWSIZE - CHARHEIGHT) / 2;
StrCenter( window, msg, len, 0, XWINDOWSIZE, y, gcs.black );
}
public void RedrawTimes()
{
char s[ 20 ];
int len;
Coord x;
FillAREA( window, 0, timesBox.top, XWINDOWSIZE,
timesBox.bot - timesBox.top + 1, gcs.white );
(void) sprintf( s, " %.1f ", d2ns( tims.start ) );
len = strlen( s );
StrLeft( window, s, len, timesBox.left, timesBox.bot, gcs.white );
(void) sprintf( s, " %.1f ", d2ns( tims.end ) );
len = strlen( s );
StrRight( window, s, len, timesBox.right - 1, timesBox.bot, gcs.white );
if( tims.cursor >= 0 )
(void) sprintf( s, "%.1f", d2ns( tims.cursor ) );
else
(void) strcpy( s, "-" );
len = strlen( s );
StrCenter( window, s, len, timesBox.left, timesBox.right, timesBox.bot,
gcs.black );
}
public void UpdateTimes( start, end )
TimeType start, end;
{
static TimeType ostart, oend;
static int slen, elen;
int len;
char s[20];
if( start != ostart )
{
(void) sprintf( s, " %.1f ", d2ns( start ) );
len = strlen( s );
if( len < slen )
FillAREA( window, timesBox.left + (len * CHARWIDTH),
timesBox.bot - CHARHEIGHT - 1, (slen - len) * CHARWIDTH,
timesBox.bot - timesBox.top + 1, gcs.white );
StrLeft( window, s, len, timesBox.left, timesBox.bot, gcs.white );
ostart = start;
slen = len;
}
if( end != oend )
{
(void) sprintf( s, " %.1f ", d2ns( end ) );
len = strlen( s );
if( len < elen )
FillAREA( window, timesBox.right - (elen * CHARWIDTH),
timesBox.bot - CHARHEIGHT - 1, (elen - len) * CHARWIDTH,
timesBox.bot - timesBox.top + 1, gcs.white );
StrRight( window, s, len, timesBox.right, timesBox.bot, gcs.white );
oend = len;
elen = len;
}
}
/*
* Redraw signal names.
*/
public void RedrawNames( rb )
BBox rb;
{
Coord x, y;
Trptr t;
int i;
rb.left = max( rb.left, namesBox.left );
rb.right = min( rb.right, namesBox.right );
rb.top = max( namesBox.top, rb.top );
rb.bot = min( namesBox.bot, rb.bot );
FillBox( window, rb, gcs.white );
for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
if( rb.top <= t->bot )
break;
x = namesBox.right - 2;
while( i != 0 and rb.bot >= t->top )
{
y = (t->bot + t->top + CHARHEIGHT) / 2;
StrRight( window, t->name, t->len, x, y, gcs.black );
if( t == selectedTrace )
UnderlineTrace( t, gcs.black );
i--;
t = t->next;
}
}
#define CursorVisible( T1, T2 ) (tims.cursor >= (T1) and tims.cursor <= (T2) )
/*
* This will redraw the missing parts of the traces. Used to selectivelly
* repaint traces or during Exposure events.
*/
public void RedrawTraces( box )
BBox *box;
{
TimeType t1, t2, tc;
BBox bg;
register Trptr t;
register int i;
t1 = XToTime( box->left ) - 1;
if( t1 < tims.start )
{
t1 = tims.start;
bg.left = traceBox.left;
}
else
bg.left = box->left;
t2 = XToTime( box->right );
if( t2 < 0 )
{
t2 = tims.end;
bg.right = traceBox.right;
}
else
{
bg.right = box->right;
if( t2 < tims.end )
t2++;
}
tc = t2;
if( t2 > tims.last )
t2 = tims.last;
bg.top = max( box->top, traceBox.top );
bg.bot = min( box->bot, traceBox.bot );
if( CursorVisible( t1, tc ) )
EraseCursor();
FillBox( window, bg, gcs.black );
for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
if( box->top <= t->bot )
break;
while( i != 0 and box->bot >= t->top )
{
if( IsVector( t ) )
DrawVector( t, t1, t2, FALSE );
else
DrawSignal( t, t1, t2 );
i--;
t = t->next;
}
if( CursorVisible( t1, tc ) )
DrawCursor();
}
/*
* Update the cache (begining of window and cursor) for traces that just
* became visible ( or were just added ).
*/
public void UpdateTraceCache( first_trace )
int first_trace;
{
register Trptr t;
register hptr h,p;
register int n, i;
register TimeType startT, cursT;
startT = tims.start;
cursT = max( tims.cursor, tims.first );
for( t = traces.first, n = 0; n < traces.disp; n++, t = t->next )
{
if( n < first_trace )
continue;
if( t->vector )
{
for( i = t->n.vec->nbits - 1; i >= 0; i-- )
{
hptr nexth;
p = t->cache[i].wind;
h = t->cache[i].cursor;
NEXTH( nexth, h );
if( h->time > cursT or nexth->time <= cursT )
{
if( p->time <= cursT ) /* whatever is closer */
t->cache[i].cursor = p;
else
t->cache[i].cursor = (hptr)&(t->n.vec->nodes[i]->head);
}
if( startT <= p->time ) /* go back */
p = (hptr) &(t->n.vec->nodes[i]->head);
NEXTH( h, p );
while( h->time < startT )
{
p = h;
NEXTH( h, h );
}
t->cache[i].wind = p;
p = t->cache[i].cursor;
NEXTH( h, p );
while( h->time <= cursT )
{
p = h;
NEXTH( h, h );
}
t->cache[i].cursor = p;
}
}
else
{
hptr nexth;
p = t->cache[0].wind;
h = t->cache[0].cursor;
NEXTH( nexth, h );
if( h->time > cursT or nexth->time <= cursT )
{
if( p->time <= cursT )
t->cache[0].cursor = p;
else
t->cache[0].cursor = (hptr) &(t->n.nd->head);
}
if( startT <= p->time )
p = (hptr) &(t->n.nd->head);
NEXTH( h, p );
while( h->time < startT )
{
p = h;
NEXTH( h, h );
}
t->cache[0].wind = p;
p = t->cache[0].cursor;
NEXTH( h, p );
while( h->time <= cursT )
{
p = h;
NEXTH( h, h );
}
t->cache[0].cursor = p;
}
}
}
private TimeType lastStart; /* last redisplay starting time */
public void FlushTraceCache()
{
lastStart = max_time;
}
/*
* Draw the traces horizontally from time1 to time2.
*/
public void DrawTraces( t1, t2 )
TimeType t1, t2;
{
TimeType endT;
register Trptr t;
int nt;
if( t1 == tims.start )
FillBox( window, traceBox, gcs.black );
else if( colors.disj == 0 and CursorVisible( tims.start, t2 ) )
EraseCursor();
if( tims.start != lastStart ) /* Update history cache */
{
int begin;
register TimeType startT;
register int n, i;
register hptr h, p;
startT = tims.start;
begin = ( startT < lastStart );
for( t = traces.first, n = traces.disp; n != 0; n--, t = t->next )
{
if( t->vector )
{
for( i = t->n.vec->nbits - 1; i >= 0; i-- )
{
p = begin ? (hptr) &(t->n.vec->nodes[i]->head) : t->cache[i].wind;
NEXTH( h, p );
while( h->time < startT )
{
p = h;
NEXTH( h, h );
}
t->cache[i].wind = p;
}
}
else
{
p = begin ? (hptr) &(t->n.nd->head) : t->cache[0].wind;
NEXTH( h, p );
while( h->time < startT )
{
p = h;
NEXTH( h, h );
}
t->cache[0].wind = p;
}
}
lastStart = tims.start;
}
endT = min( t2, tims.last );
for( t = traces.first, nt = traces.disp; nt != 0; nt--, t = t->next )
{
if( IsVector( t ) )
DrawVector( t, t1, endT, (t1 != tims.start) ? TRUE : FALSE );
else
DrawSignal( t, t1, endT );
}
if( CursorVisible( tims.start, t2 ) )
DrawCursor();
}
/*
* Draw a 1 bit trace.
*/
private void DrawSignal( t, t1, t2 )
Trptr t;
register TimeType t1, t2;
{
register hptr h;
register int val, change;
int x1, x2;
if( t1 >= tims.last )
return;
h = t->cache[0].wind;
if( t1 != tims.start )
{
register hptr n;
NEXTH( n, h );
while( n->time < t1 )
{
h = n;
NEXTH( n, n );
}
}
x1 = TimeToX( t1 );
while( t1 < t2 )
{
val = h->val;
while( h->time < t2 and h->val == val )
NEXTH( h, h );
if( h->time > t2 )
{
change = FALSE;
t1 = t2;
}
else
{
change = ( h->val != val );
t1 = h->time;
}
x2 = TimeToX( t1 );
switch( val )
{
case LOW :
HLine( window, x1, x2, t->bot, gcs.traceFg );
break;
case HIGH :
HLine( window, x1, x2, t->top, gcs.traceFg );
break;
case X :
if( x1 > traceBox.left + 1 )
x1++;
FillAREA( window, x1, t->top, x2 - x1 + 1, t->bot - t->top + 1,
gcs.xpat );
break;
}
if( change )
VLine( window, x2, t->bot, t->top, gcs.traceFg );
x1 = x2;
}
}
public hptr tmpHBuff[ 400 ];
/*
* Draw bus trace.
*/
private void DrawVector( t, t1, t2, clr_bg )
register Trptr t;
register TimeType t1, t2;
int clr_bg;
{
hptr *start, *changes;
TimeType firstChange;
int x1, x2, xx, mid, nbits, strlen, strwidth;
if( t1 >= tims.last )
return;
nbits = t->n.vec->nbits;
start = tmpHBuff;
changes = &(tmpHBuff[ nbits ]);
strlen = (nbits + t->bdigit - 1) / t->bdigit;
strwidth = CHARWIDTH * strlen + 1;
{
register hptr h, *s;
register int n, val;
s = start; /* initialize start array */
if( t1 != tims.start )
{
register hptr p;
firstChange = tims.start;
for( n = nbits - 1; n >= 0; n-- )
{
p = t->cache[n].wind;
val = p->val;
NEXTH( h, p );
while( h->time < t1 )
{
if( h->val != val )
{
if( h->time > firstChange )
firstChange = h->time;
val = h->val;
}
p = h;
NEXTH( h, h );
}
s[n] = p;
}
}
else
{
firstChange = tims.start;
for( n = nbits - 1; n >= 0; n-- )
s[n] = t->cache[n].wind;
}
{ /* Initialize changes array */
register hptr *ch = changes;
register TimeType tm = tims.end;
for( n = nbits - 1; n >= 0; n-- )
{
h = s[n];
val = h->val;
while( h->time < tm and h->val == val )
NEXTH( h, h );
ch[n] = h;
}
}
}
mid = (t->top + t->bot + CHARHEIGHT) / 2;
xx = TimeToX( t1 );
x2 = TimeToX( t2 );
x1 = TimeToX( firstChange );
HLine( window, xx, x2, t->top, gcs.traceFg );
HLine( window, xx, x2, t->bot, gcs.traceFg );
if( clr_bg and t1 != tims.start and (xx - x1) > strwidth )
FillAREA( window, x1+1, mid - CHARHEIGHT+1, xx - x1+1, CHARHEIGHT,
gcs.traceBg );
while( t1 < t2 )
{
{ /* find nearest change in time */
register hptr *ch;
register int n;
t1 = tims.end + 1;
for( ch = changes, n = nbits - 1; n >= 0; n-- )
{
if( ch[n]->time < t1 )
t1 = ch[n]->time;
}
}
if( t1 <= t2 ) /* change before t2 => draw it */
{
register int n;
x2 = TimeToX( t1 );
n = (x2 == traceBox.left+1) ? 2 : (x2 == traceBox.right-1) ? 1 : 0;
VLine( window, x2, t->bot, t->top, gcs.traceFg );
XCopyArea( display, pix.tops[n], window, gcs.traceBg, 0, 0, 3, 2,
x2 - 1, t->top );
XCopyArea( display, pix.bots[n], window, gcs.traceBg, 0, 0, 3, 2,
x2 - 1, t->bot - 1 );
}
else /* change after t2 */
{
register TimeType tm;
tm = min( t1, min( tims.end, tims.last ) );
x2 = TimeToX( tm );
}
if( x2 - x1 > strwidth )
{
char *str;
str = HistToStr( start, nbits, t->bdigit, 1 );
StrCenter( window, str, strlen, x1, x2, mid, gcs.traceFg );
}
{
register hptr h;
register hptr *ch, *s;
register int n, val;
register TimeType tm = tims.end;
for( s = start, ch = changes, n = nbits - 1; n >= 0; n-- )
{
if( ch[n]->time == t1 )
{
h = s[n] = ch[n];
val = h->val;
while( h->time < tm and h->val == val )
NEXTH( h, h );
ch[n] = h;
}
}
}
x1 = x2;
}
}
private void UpdateTraces( start, end )
TimeType start, end;
{
if( not (windowState.iconified or windowState.tooSmall) )
{
UpdateScrollBar();
RedrawTimes();
DrawTraces( start, end );
}
}
private void ScrollTraces( endT )
TimeType endT;
{
tims.start = endT - tims.steps / 2;
tims.end = tims.start + tims.steps;
UpdateTraces( tims.start, endT );
}
/*
* Update the trace window so that endT is shown. If the update fits in the
* window, simply draw the missing parts. Otherwise scroll the traces,
* centered around endT.
*/
public void UpdateWindow( endT )
TimeType endT;
{
TimeType lastT;
DisableInput();
if( freezeWindow )
{
updatePending = TRUE;
updPendTime = endT;
}
else
{
lastT = tims.last;
tims.last = endT;
if( endT <= tims.end )
{
if( lastT >= tims.start )
UpdateTraces( lastT, endT );
else if( autoScroll )
ScrollTraces( endT );
else if( endT > tims.start )
UpdateTraces( tims.start, endT );
}
else /* endT > tims.end */
{
if( autoScroll )
ScrollTraces( endT );
else if( lastT < tims.end )
UpdateTraces( lastT, tims.end );
}
}
EnableInput();
}
/*
* Erase/Redraw the cursor.
*/
private void EraseCursor()
{
Coord x;
x = TimeToX( tims.cursor );
FillAREA( window, x, traceBox.top, 1, traceBox.bot - traceBox.top,
gcs.curs_off );
}
private void DrawCursor()
{
Coord x;
x = TimeToX( tims.cursor );
FillAREA( window, x, traceBox.top, 1, traceBox.bot - traceBox.top,
gcs.curs_on );
}
public void DoCursor( ev )
XButtonEvent *ev;
{
Trptr t;
TimeType time;
char tbuff[15];
if( not (ev->state & ShiftMask) )
{
MoveCursorToPos( ev->x );
return;
}
t = GetYTrace( ev->y );
time = XToTime( ev->x );
if( t == NULL or time < 0 or time > tims.last )
{
XBell( display, 0 );
return;
}
(void) sprintf( tbuff, "%.1f", d2ns( time ) );
PRINTF( "\n%s @ %s: value=", t->name, tbuff );
{
register hptr h, p;
register int n;
register char *val, *inp;
int nbits;
val = (char *) tmpHBuff;
if( IsVector( t ) )
nbits = t->n.vec->nbits;
else
nbits = 1;
inp = &(val[nbits]);
*inp++ = '\0';
inp[nbits] = '\0';
for( n = nbits - 1; n >= 0; n-- )
{
p = t->cache[n].wind;
NEXTH( h, p );
while( h->time <= time )
{
p = h;
NEXTH( h, h );
}
val[n] = "0X 1"[ p->val ];
inp[n] = "-i"[p->inp];
}
PRINTF( "%s, input=%s", val, inp );
}
}
private void MoveCursorToPos( x )
Coord x;
{
register int i;
register Trptr t;
register TimeType time;
char s[ 20 ];
static int olen = 1;
time = XToTime( x );
if( time == tims.cursor or time < tims.start or time > tims.end )
return;
if( CursorVisible( tims.start, tims.end ) )
EraseCursor();
tims.cursor = time;
DrawCursor();
(void) sprintf( s, "%.1f", d2ns( time ) );
i = strlen( s );
if( i < olen )
{
FillAREA( window, (timesBox.left+timesBox.right+(olen * CHARWIDTH))/2,
timesBox.bot - CHARHEIGHT - 1, olen * CHARWIDTH,
timesBox.bot - timesBox.top + 1, gcs.white );
}
StrCenter( window, s, i, timesBox.left, timesBox.right, timesBox.bot,
gcs.black );
for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
{
register hptr h, p;
if( IsVector( t ) )
{
register int n;
for( n = t->n.vec->nbits - 1; n >= 0; n-- )
{
p = t->cache[n].wind;
NEXTH( h, p );
while( h->time <= time )
{
p = h;
NEXTH( h, h );
}
t->cache[n].cursor = p;
}
}
else
{
p = t->cache[0].wind;
NEXTH( h, p );
while( h->time <= time )
{
p = h;
NEXTH( h, h );
}
t->cache[0].cursor = p;
}
}
DrawCursVal( cursorBox );
}
private char *StrMap[] = { "0", "X", "", "1" };
/*
* Display signal values under cursor.
*/
public void DrawCursVal( rb )
BBox rb;
{
Coord y;
Trptr t;
int i, len;
char *val;
rb.left = max( rb.left, cursorBox.left );
rb.right = min( rb.right, cursorBox.right );
rb.top = max( cursorBox.top, rb.top );
rb.bot = min( cursorBox.bot, rb.bot );
FillBox( window, rb, gcs.white );
if( tims.cursor < tims.first or tims.cursor > tims.last )
return;
for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
if( rb.top <= t->bot )
break;
while( i != 0 and rb.bot >= t->top )
{
y = ( t->bot + t->top + CHARHEIGHT ) / 2;
val = IsVector( t ) ?
HistToStr( &(t->cache[0].cursor), t->n.vec->nbits, t->bdigit, 2 ) :
StrMap[ t->cache[0].cursor->val ];
len = strlen( val );
StrCenter( window, val, len, cursorBox.left, cursorBox.right, y,
gcs.black );
i--;
t = t->next;
}
}
public void ExpandCursVal( t )
Trptr t;
{
char *val;
int nbits;
nbits = IsVector( t ) ? t->n.vec->nbits : 1;
val = HistToStr( &(t->cache[0].cursor), nbits, 1, 2 );
PRINTF( "\n %s : value=%s", t->name, val );
{
register int n;
register Cache *c;
register char *s;
for( n = 0, s = val, c = t->cache; n < nbits; n++ )
*s++ = ( c[n].cursor->inp) ? 'i' : '-';
}
PRINTF( " input=%s", val );
}